const conf = require('../../conf/conf.json')
const { Filter } = require("../../display/filters")
const { Display, translateTower, translateBloon } = require("../../display/general")
const { parseProperties, parseCategory, parseAreaType } = require("../../util/enums")
const { ignoreFunction } = require("../../util/ignore")
const { getModelType } = require("../../util/utils")

const models = {}

//----------------------------------------------------
// bloons
//----------------------------------------------------

models.FilterAllExceptTargetModel = m => {
    return new Filter('targetOnly', 'only affects the target')
}

models.FilterAllModel = m => {
    return new Filter('ignoreAll', 'ignores all')
}

models.FilterBloonIfDamageTypeModel = m => {
    return m.ifCantHitBloonProperties ? new Filter('ignoreIfCannotDamage',
        `can not affect ${parseProperties(m.ifCantHitBloonProperties)} if cannot damage`,
        parseProperties(m.ifCantHitBloonProperties, conf.translate)) : null
}

models.FilterBloonsToWithinAngleModel = m => {
    return null
}

models.FilterFrozenBloonsModel = m => {
    return new Filter('filterFrozen', 'can not affect frozen bloons')
}

models.FilterGlueLevelModel = m => {
    return new Filter('filterGlueLevel', `can not affect bloons with glue level >= ${m.glueLevel}`, m.glueLevel)
}

models.FilterIfAttackHasTargetModel = m => {
    return null
}

models.FilterInvisibleModel = m => {
    return m.isActive ? new Filter('filterCamo', 'can not affect camo') : null
}

models.FilterInvisibleSubIntelModel = models.FilterInvisibleModel

models.FilterMarkedToPopModel = ignoreFunction

models.FilterMoabModel = m => {
    return new Filter(`filter${m.flip ? 'Out' : 'In'}Moabs`, `can ${m.flip ? 'not' : 'only'} affect blimps`)
}

models.FilterMutatedTargetModel = m => {
    if (m.mutationIds.length === 0) {
        return null
    }
    if (m.mutationIds.length === 1 && m.mutationIds[0] === 'Ice') {
        return models.FilterFrozenBloonsModel(m)
    }
    return new Filter(
        `filter${m.inverse ? 'In' : 'Out'}Status`,
        `can ${m.inverse ? 'only' : 'not'} affect bloons with statuses ${m.mutationIds.join('/')}`,
        [m.mutationIds.map(Display.mutationId).join('/')]
    )
}

models.FilterOfftrackModel = m => {
    return new Filter('filterOffTrack', 'can not affect bloons off track')
}

models.FilterOnlyCamoInModel = m => {
    return new Filter('filterOnlyCamo', 'can only affect camo')
}

models.FilterOutBloonModel = m => {
    return new Filter('filterBloonId', `can not affect ${m.bloonId}`, translateBloon(m.bloonId))
}

models.FilterOutOffscreenModel = m => {
    return new Filter(
        'filterOffScreen' + (m.includeBloonRadius ? '' : 'Fully'),
        'can not affect bloons out of screen'
    )
}

models.FilterOutTagModel = m => {
    const addMutationIds = m.disableWhenSupportMutatorIDs &&
        m.disableWhenSupportMutatorIDs.length &&
        m.disableWhenSupportMutatorIDs[0] !== 'false'
    if (m.tag === 'Ice') {
        return models.FilterFrozenBloonsModel(m)
    }
    if ((['Miniboss']).includes(m.tag)) {
        return null
    }
    return new Filter(
        'filterOutTags' + (addMutationIds ? 'WithoutStatus' : ''),
        `can not affect ${m.tag}` + (addMutationIds ? ` unless with ${m.disableWhenSupportMutatorIDs.join('/')}` : ''),
        translateBloon(m.tag),
        addMutationIds ? m.disableWhenSupportMutatorIDs.map(Display.mutationId).join('/') : null
    )
}

models.FilterOveridingMutatedTargetModel = ignoreFunction

models.FilterParentTowerRangeModel = ignoreFunction

// camo/regrow/fortified/moabs
models.FilterWithTagModel = m => {
    return new Filter(
        `filter${m.inclusive ? 'Out' : 'In'}Tags`,
        `can ${m.inclusive ? 'not' : 'only'} affect ${m.tag} bloons`,
        translateBloon(m.tag)
    )
}

models.FilterWithTagsModel = m => {
    return new Filter(
        `filter${m.inclusive ? 'Out' : 'In'}Tags`,
        `can ${(m.inclusive ? 'not' : 'only')} affect ${m.tags.join('/')}`,
        m.tags.map(translateBloon).join('/')
    )
}

models.FilterTargetAngleModel = m => {
    return null
}

models.FilterWithChanceModel = m => {
    return new Filter(
        'filterChance',
        `only has ${m.filterChance}% chance to hit`,
        Display.percent(m.filterChance)
    )
}

//----------------------------------------------------
// towers
//----------------------------------------------------

models.FilterInBaseTowerIdModel = m => {
    return new Filter(
        `filterInTowers`,
        `can only affect ${m.baseIds.join('/')}`,
        m.baseIds.map(translateTower).join('/')
    )
}

models.FilterInOwnedByModel = m => {
    return null
}

models.FilterInSetModel = m => {
    return new Filter(
        `filterInTowerSet`,
        `can only affect ${parseCategory(m.towerSet)}`,
        parseCategory(m.towerSet)
    )
}

models.FilterInTowerTiersModel = m => {
    return new Filter(
        'filterInTowerTiersRange',
        `can only affect tower path in ${m.path1MinTier}${m.path2MinTier}${m.path3MinTier}-${Math.min(m.path1MaxTier, 5)}${Math.min(m.path2MaxTier, 5)}${Math.min(m.path3MaxTier, 5)}`,
        `${m.path1MinTier}${m.path2MinTier}${m.path3MinTier}`,
        `${Math.min(m.path1MaxTier, 5)}${Math.min(m.path2MaxTier, 5)}${Math.min(m.path3MaxTier, 5)}`
    )
}

models.FilterParagonModel = m => {
    return new Filter(
        `filter${m.inclusive ? 'In' : 'Out'}Paragon`,
        `can ${m.inclusive ? 'only' : 'not'} affect paragons`
    )
}

models.FilterTowerByPlaceableAreaModel = m => {
    return new Filter(
        `filterTowerArea${m.exclusive ? 'Exclusive' : ''}`,
        `can only affect tower${m.exclusive ? ' exclusively' : ''} on ${m.areaTypes.map(parseAreaType).join('/')}`,
        m.areaTypes.map(e => parseAreaType(e, conf.translate)).join('/')
    )
}

models.FilterTowerParentModel = m => {
    return new Filter('filterOutParentTower', 'can not affect parent tower')
}

function parseFilter(f) {
    const type = getModelType(f)
    if (models[type]) return models[type](f)
    return f
}

function parseFilters(f) {
    if (!f) {
        return []
    }
    if (Array.isArray(f)) {
        return f.map(parseFilter)
    }
    return [parseFilter(f)]
}

module.exports = {
    parseFilters,
}